﻿using commonImportPlugin.Common;
using commonImportPlugin.Config;
using ICMS.PluginInterfaces;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace commonImportPlugin.Decrypt
{
    public class DecryptZGNYYHbase
    {
        CommonUtil commonUtil = CommonUtil.GetInstance();
        bool isOpenHsmSucceed =false;
        #region ==============中国农业银行数据解密函数===============
        //金融加密机实例
        private IHSM[] _bankHSMs;
        //加密机标记
        private int _bankHSMToken;
        //项目ID
        private string _projectId;
        //银行ID
        private string _hsmBankId;

        public DecryptZGNYYHbase(Context _context)
        {
            this._bankHSMs = _context.pbocHSMs;
            this._projectId = _context.projectId;
            this._hsmBankId = _context.hsmBankId;
            
        }
        /// <summary>
        /// 连接加密机
        /// </summary>
        /// <returns></returns>
        public int hsmConnect()
        {
            try
            {
                int bankHSMToken = this._bankHSMs.FirstOrDefault().Connect(this._projectId, this._hsmBankId);
                this._bankHSMToken = bankHSMToken;
                isOpenHsmSucceed = true;
                return bankHSMToken;
            }
            catch (Exception e)
            {                
                throw new Exception("打开加密机失败!\nerror:"+e.Message);
            }
            
        }
        /// <summary>
        /// 关闭加密机
        /// </summary>
        public void hsmClose()
        {
            try
            {
                if (!isOpenHsmSucceed)
                    return;                
                this._bankHSMs[0].Close(this._bankHSMToken);
            }
            catch (Exception)
            {
                ;
                //throw new Exception("关闭加密机失败！"+e.Message);
            }
            
        }
             
        private ReturnComposite Decrypt(string beforeDecrypt)
        {
            try
            {
                ReturnComposite ret = null;
                //生产密钥
                for (int i = 0; i <=20; i++)
                {
                    ret = this._bankHSMs.FirstOrDefault().CoreMethod(this._bankHSMToken, 1, "I:KEK", "257", "ECB", beforeDecrypt, "0000000000000000", string.Empty, string.Empty);
                    if (ret.Value == 0)
                    {
                        break;
                    }
                    else
                    {
                        hsmClose();
                        System.Threading.Thread.Sleep(100);
                        this._bankHSMToken = hsmConnect();
                    }
                }
                return ret; //明文
            }
            catch (Exception)
            {
                return null;
            }
           
        }

        /// <summary>
        /// ASCII码转BCD码
        /// </summary>
        /// <param name="hex"></param>
        /// <param name="charset"></param>
        /// <returns></returns>
        private string ASCIIToBCD(string hex, string charset)
        {
            hex = hex.Replace(" ", "");
            hex = hex.Replace(",", "");
            hex = hex.Replace("\\", "");
            hex = hex.Replace("\n", "");
            if ((hex.Length % 2) != 0)
            {
                hex += "20";
            }

            byte[] bytes = new byte[hex.Length / 2];

            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = byte.Parse(hex.Substring(i * 2, 2), NumberStyles.HexNumber);
            }
            Encoding enc = Encoding.GetEncoding(charset);
            return enc.GetString(bytes);
        }

        /// <summary>
        /// 获取磁条数据
        /// </summary>
        /// <param name="beforeDecryptData">原始磁条数据</param>
        /// <param name="bankCard"></param>
        /// <param name="decData"></param>
        /// <returns></returns>
        public bool GetTrackData(string beforeDecryptData,out string decData)
        {
            var msg = string.Empty;
            decData = string.Empty;
            bool flag = false;

            var rc = Decrypt(beforeDecryptData);
            if (rc != null && rc.Value == 0)
            {
                msg = rc.Word;
                while (true)
                {
                    if (msg.EndsWith("00"))
                        msg = msg.Substring(0, msg.Length - 2);
                    else
                    {
                        if (msg.EndsWith("80"))
                            msg = msg.Substring(0, msg.Length - 2);
                        break;          //可以停止了
                    }
                }
                decData = ASCIIToBCD(msg, "ASCII");
                flag = true;
            }
            return flag;
        }

        #endregion

        #region ===================其他辅助函数======================
        /// <summary>
        /// 检查磁条数据格式
        /// </summary>
        /// <param name="trackData"></param>
        /// <returns></returns>
        public bool CheckTrackDatas(string trackData)
        {
            string checkRegex=@"[%][?][;]6228[0-9]{15}[=][0-9]{17}[?][_][;]99622[0-9]{16}[=][0-9]{39}[?]";
            if (!Regex.IsMatch(trackData, checkRegex))
                throw new Exception("提取的磁条格式不正确！");
            return true;

        }
        /// <summary>
        /// 出现解密失败的数据咨询是否继续
        /// </summary>
        /// <param name="originDataCounts">原始数据量</param>
        /// <param name="succeedDecrptDataCounts">成功解密的数据量</param>
        /// <param name="failDatas">失败的日志</param>
        /// <returns>true 继续</returns>
        public bool IsContinueDeal(int originDataCounts, string taskId, int succeedDecrptDataCounts, List<string> failDatas)
        {
            string errorMessages = string.Format("\n存在解密失败的数据!\n数据量共：{0}条，解密成功的共：{1}条，其中共：{2}条解密失败\n" +
                    "导致的原因：可能由于加密机不稳定或数据有问题,\n选择”是“将成功解密的继续导入,”否“,查看失败日志终止导入\n" +
                   "注：重复导入将会自动剔除已导入的数据", originDataCounts, succeedDecrptDataCounts, failDatas.Count - 1);

            ///////////////生成日志文件///////////////
            failDatas[0] = string.Format("解密磁条数据时共有如下{0}条数据出现异常!其银行卡号如下：", failDatas.Count - 1);

            string errorFilePath = string.Format(@"{0}\导入插件解密结果\{1}(解密磁条失败).txt",
                Application.StartupPath, taskId);

            commonUtil.ListStringToTxtFile(failDatas, errorFilePath);

            ///////////////提示/////////////
            bool isContinue = commonUtil.WhetherContinue(errorMessages);
            if (!isContinue)
            {
                commonUtil.OpenFolderAndSelectFile(errorFilePath);
                throw new Exception("导入失败，存在解密失败的数据");
            }
            return true;
        }

        #endregion
    }

}
